//
//  NfcManager.swift
//  CommonKit
//
//  Created by Brice on 2021/1/11.
//

import UIKit
import CoreNFC

class NfcManager: NSObject {

    @available(iOS 11.0, *)
    private lazy var nfcSession: NFCNDEFReaderSession? = {
        return nil
    }()
    // nfc检测成功后显示的文本
    private var nfcSuccessMessage = ""
    
    private var responseCallBack: WVJBResponseCallback?
    
    // 待写入数据
    private var nfcWriteMessages: [String]?
    
    // nfc模式：0读，1写
    private var nfcModel: Int = 0
    
    // 创建并开启nfc会话开关
    private func startNFC(model: Int, isOnlyReadOnce:Bool, alertMessage:String, responseCallback: WVJBResponseCallback?) {
        
        let errorMsg = "error:苹果手机需要iPhone7以上且系统版本11.0及以上才支持NFC读取，而且系统版本13.0及以上才支持NFC写入功能"
        
        if #available(iOS 11.0, *) {
            if !NFCNDEFReaderSession.readingAvailable {
                responseCallback?(errorMsg)
                return
            }
        } else {// 低于 iOS 11.0 的系统抛出错误提示
            responseCallback?(errorMsg)
            return
        }
        if #available(iOS 13.0, *) {
            // 系统13.0以下不支持写入，抛出提示
        } else {
            if (model == 1) {
                responseCallback?(errorMsg)
                return
            }
        }
        
        if #available(iOS 11.0, *) {
                
            if nfcSession == nil {
                /**
                   delegate: 当前nfc会话对象会持有一个self的弱引用，继承自NFCNDEFReaderSessionDelegate
                   queue: 一个队列用于接收代理回调的事件，如果传入nil，系统会创建一个串行队列并被会话对象持有
                   invalidateAfterFirstRead: 会话对象读取一个还是多个NDEF标签。true：读取一个后结束会话，false：读取多个标签，需实现 readerSession:didDetectTags:代理方法
                 */
                nfcSession = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: isOnlyReadOnce)
                nfcSession?.alertMessage = alertMessage
            }
            
            nfcModel = model
            
            nfcSession?.begin()
            
            responseCallBack = responseCallback
        }
    }
    
    
    /// 注册NFC读取事件
    /// - Parameters:
    ///   - data: [String: Any]
    ///   - responseCallback: 成功回调
    public func registerNFCStartReader(data: Any?, responseCallback: WVJBResponseCallback?) {
        
        var isOnlyReadOnce = true
        
        var tipMsg = "已准备好读取标签信息"
        
        nfcSuccessMessage = "标签信息读取成功"
        
        if let parms = data as? [String: Any] {
            
            if let flag = parms["isOnlyReadOnce"] as? Bool {
                
                isOnlyReadOnce = flag
            }
            
            if let alertMsg = parms["alertMessage"] as? String {
                
                tipMsg = alertMsg
            }
            
            if let successMsg = parms["successMessage"] as? String {
                
                nfcSuccessMessage = successMsg
            }
        }
        
        startNFC(model: 0, isOnlyReadOnce: isOnlyReadOnce, alertMessage: tipMsg, responseCallback: responseCallback)
    }
    
    /// 注册nfc开始监听写入事件
    public func registerNFCStartWriter(data: Any?, responseCallback: WVJBResponseCallback?) {
        
        guard let params = data as? [String: Any], let writeMsgs = params["messages"] as? [String] else {
            
            responseCallback?("error: 写入信息为空或不是字符数组")
            return
        }
        
        nfcWriteMessages = writeMsgs
        
        nfcSuccessMessage = "标签信息写入成功"
        
        var alertMessage = "将你的手机贴近一张可读写的标签卡片，即可写入数据"
        
        if let alertMsg = params["alertMessage"] as? String {
            
            alertMessage = alertMsg
        }
        
        if let successMsg = params["successMessage"] as? String {
            
            nfcSuccessMessage = successMsg
        }
        
        startNFC(model: 1, isOnlyReadOnce: true, alertMessage: alertMessage, responseCallback: responseCallback)
    }
    
    /// 注册nfc停止扫描接口
    public func registerNFCStop(responseCallback: WVJBResponseCallback?) {
        
        if #available(iOS 11.0, *) {
            
            self.closeNFC()
            
            self.responseCallBack = nil
            
        } else {
            
            responseCallback?("-1error:设备或系统不支持NFC功能")
        }
    }
    
    
    @available(iOS 11.0, *)
    private func closeNFC(errorMessage: String? = nil, alertMessage:String? = nil) {
        
        if errorMessage != nil {
            
            if #available(iOS 13.0, *) {
                
                nfcSession?.invalidate(errorMessage: errorMessage!)
                
            } else {
                
                nfcSession?.alertMessage = errorMessage!
            }
            
            self.responseCallBack?("error:\(errorMessage!)")
            
        } else {
            
            if let msg = alertMessage {
                
                nfcSession?.alertMessage = msg
                
                self.responseCallBack?("success:\(msg)")
            }
            
            nfcSession?.invalidate()
        }
        
        nfcSession = nil
    }
    
    @available(iOS 11.0, *)
    private func nfcReaderFinish(message: NFCNDEFMessage?) {
        
        self.nfcSession?.alertMessage = self.nfcSuccessMessage
        
        self.closeNFC()
        
        var nfcDataString = ""
        
        if let records = message?.records {
            
            for item in records {
                
                let type = String(data: item.type, encoding: .utf8) ?? ""
                
                let id = String(data: item.identifier, encoding: .utf8) ?? ""
                
                let data = String(data: item.payload, encoding: .utf8) ?? ""
                
                if !nfcDataString.isEmpty {
                    
                    nfcDataString += ";"
                }
                
                let dataFilter = data.replacingOccurrences(of: "\0", with: "").removingPercentEncoding ?? ""
                
                nfcDataString = "\(nfcDataString)id=\(id)&type=\(type)&payload=\(dataFilter)"
                
            }
        }
        
        self.responseCallBack?(nfcDataString)
    }
    
}


@available(iOS 11.0, *)
extension NfcManager: NFCNDEFReaderSessionDelegate {
    
    func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
        
        let nsError = error as NSError
        
        var errorMsg = "error:\(nsError.localizedDescription)"
        
        if nsError.code == 1 {
            
            errorMsg = "error:设备或系统不支持NFC功能"
        }
        
        if nsError.code < 200 {
            
            self.responseCallBack?(errorMsg)
        }
        
        self.closeNFC()
    }
    
    func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) {
        
        print("success:NFC扫描已启动")
    }
    
    @available(iOS 13.0, *)
    func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) {
        
        if let tag = tags.first {
        
            session.connect(to: tag) { (error) in
                
                if let err = error {
                    
                    self.closeNFC(errorMessage: err.localizedDescription)
                    
                    return
                }
                
                // 读数据
                if self.nfcModel == 0 {
            
                    tag.readNDEF(completionHandler: { (message, error) in
                        
                        if let err = error {
                            
                            self.closeNFC(errorMessage: err.localizedDescription)
                            
                            return
                        }
                        
                        self.nfcReaderFinish(message: message)
                    })
                    
                    return
                }
                
                // 写数据
                if self.nfcModel == 1 {
                    
                    tag.queryNDEFStatus { (status, size, error) in
                        
                        if let err = error {
                            
                            self.closeNFC(errorMessage: err.localizedDescription)
                            
                            return
                        }
                        
                        if status == .readOnly {
                            
                            self.closeNFC(errorMessage: "只读标签不能写入信息")
                            
                            return
                        }
                        
                        if status == .notSupported {
                            
                            self.closeNFC(errorMessage: "不支持向该标签写入信息")
                            
                            return
                        }
                        
                        if status == .readWrite {
                        
                            guard let msgs = self.nfcWriteMessages else {
                                
                                self.closeNFC(errorMessage: "写入信息不能为空值")
                                
                                return
                            }
                            
                            var nfcPayloads:[NFCNDEFPayload] = []
                            
                            for msg in msgs {
                                
                                if let msgData = msg.data(using:.utf8)
                                    , let emptyData = "".data(using: .ascii)
                                    , let tData = "T".data(using: .ascii) {
                                
                                    nfcPayloads.append(NFCNDEFPayload(format: .nfcWellKnown, type: tData, identifier: emptyData, payload: msgData))
                                }
                            }
                            
                            let nfcMessage = NFCNDEFMessage(records: nfcPayloads)
                            
                            if nfcMessage.length > size {
                                
                                self.closeNFC(errorMessage: "写入信息超出标签内存大小(\(size)B")
                                
                                return
                            }
                            
                            tag.writeNDEF(nfcMessage) { (error) in
                                
                                if let err = error {
                                    
                                    self.closeNFC(errorMessage: err.localizedDescription)
                                    
                                    return
                                }
                                
                                self.closeNFC(errorMessage: nil, alertMessage: self.nfcSuccessMessage)
                            }
                        }
                    }
                }
            }
            
        } else {
            
            self.nfcReaderFinish(message: nil)
        }
    }
    
    @available(iOS 11.0, *)
    func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
        
        nfcReaderFinish(message: messages.first)
    }
}
